// --------------------------------------------------------------------------------------------------------------------

// <copyright file="Assert.cs" company="Social Development Spb">

//   Copyright (c) Social Development Spb 2009

// </copyright>

// <summary>

//   Defines assertion methods.

// </summary>

// --------------------------------------------------------------------------------------------------------------------


using Diagnostics.Annotations;
using System;
using System.Diagnostics;
using System.Globalization;

namespace Diagnostics
{
    #region Imported Namespaces

    

    #endregion


    /// <summary>
    /// Defines assertion methods.
    /// </summary>
    public static class Assert
    {
        #region Constants and Fields

        private const string _argumentNullMessage = "Null argument specified.";
        private const string _invalidIdentifierMessage = "Invalid identifier.";
        private const string _stringIsNullOrEmptyMessage = "String is either null or empty.";
        private const string _unexpectedFalseCondition = "Unexpected false condition.";
        private const string _unexpectedNonNullValueMessage = "Unexpected non null value.";
        private const string _unexpectedNullValueMessage = "Unexpected null value.";
        private const string _unexpectedTrueCondition = "Unexpected true condition.";
        private const string _unexpectedTypeMessage = "An unexpected object type.";
        private const string _notSameMessage = "Provided objects are different";

        #endregion


        #region Public Methods

        /// <summary>
        /// Generates assert if specified method argument is <c>null</c>.
        /// </summary>
        /// <param name="argument">
        /// An argument value to check.
        /// </param>
        /// <param name="argumentName">
        /// A name of an argument.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void ArgumentNotNull(
            [AssertionCondition(AssertionConditionType.IS_NOT_NULL)] object argument, string argumentName)
        {
            Debug.Assert(
                argument != null, _argumentNullMessage, string.Format(CultureInfo.CurrentCulture, "{0} is null.", argumentName));
        }


        /// <summary>
        /// Generates assert if specified method argument is <c>null</c>.
        /// </summary>
        /// <typeparam name="T">
        /// Argument type.
        /// </typeparam>
        /// <param name="argument">
        /// An argument value to check.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void ArgumentNotNull<T>([AssertionCondition(AssertionConditionType.IS_NOT_NULL)] T argument)
            where T : class
        {
            Debug.Assert(
                argument != null, 
                _argumentNullMessage, 
                string.Format(CultureInfo.CurrentCulture, "{0} is null.", typeof(T).Name));
        }


        /// <summary>
        /// Generates assert if specified method argument is <c>null</c>.
        /// </summary>
        /// <param name="argument">
        /// An argument to check.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void ArgumentNotNull([AssertionCondition(AssertionConditionType.IS_NOT_NULL)] object argument)
        {
            Debug.Assert(argument != null, _argumentNullMessage);
        }


        /// <summary>
        /// Emits the specified error message.
        /// </summary>
        /// <param name="message">
        /// A <see cref="System.String"/> containing error message to display.
        /// </param>
        [Conditional("DEBUG")]
        public static void Fail(string message)
        {
            Debug.Fail(message);
        }


        /// <summary>
        /// Asserts whether the specified condition is <c>false</c>.
        /// </summary>
        /// <param name="condition">
        /// The evaluation condition.
        /// </param>
        /// <param name="message">
        /// A <see cref="System.String"/> containing a message.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsFalse([AssertionCondition(AssertionConditionType.IS_FALSE)] bool condition, string message)
        {
            Debug.Assert(!condition, message);
        }


        /// <summary>
        /// Asserts whether the specified condition is <c>false</c>.
        /// </summary>
        /// <param name="condition">
        /// The evaluation condition.
        /// </param>
        /// <param name="messageFormat">
        /// A <see cref="System.String"/> containing a message format.
        /// </param>
        /// <param name="arguments">
        /// An array of message arguments to format.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsFalse(
            [AssertionCondition(AssertionConditionType.IS_FALSE)] bool condition, 
            string messageFormat, 
            params object[] arguments)
        {
            Debug.Assert(!condition, string.Format(CultureInfo.CurrentCulture, messageFormat, arguments));
        }


        /// <summary>
        /// Asserts whether the specified condition is <c>false</c>.
        /// </summary>
        /// <param name="condition">
        /// The evaluation condition.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsFalse([AssertionCondition(AssertionConditionType.IS_FALSE)] bool condition)
        {
            Debug.Assert(!condition, _unexpectedTrueCondition);
        }


        /// <summary>
        /// Asserts whether specified object is not <c>null</c>.
        /// </summary>
        /// <param name="expected">
        /// An <see cref="System.Object"/> to check.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsNotNull([AssertionCondition(AssertionConditionType.IS_NOT_NULL)] object expected)
        {
            Debug.Assert(expected != null, _unexpectedNullValueMessage);
        }


        /// <summary>
        /// Asserts whether specified object is not <c>null</c>.
        /// </summary>
        /// <param name="expected">
        /// An <see cref="System.Object"/> to check.
        /// </param>
        /// <param name="message">
        /// A message to display.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsNotNull(
            [AssertionCondition(AssertionConditionType.IS_NOT_NULL)] object expected, string message)
        {
            Debug.Assert(expected != null, _unexpectedNullValueMessage, message);
        }


        /// <summary>
        /// Asserts whether specified object is not <c>null</c>.
        /// </summary>
        /// <param name="expected">
        /// An <see cref="System.Object"/> to check.
        /// </param>
        /// <param name="messageFormat">
        /// A composite format <see cref="string"/>.
        /// </param>
        /// <param name="arguments">
        /// An array of objects to format.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsNotNull(
            [AssertionCondition(AssertionConditionType.IS_NOT_NULL)] object expected, 
            string messageFormat, 
            params object[] arguments)
        {
            Debug.Assert(
                expected != null, 
                _unexpectedNullValueMessage, 
                string.Format(CultureInfo.CurrentCulture, messageFormat, arguments));
        }


        /// <summary>
        /// Asserts that the specified string is not <c>null</c> or empty.
        /// </summary>
        /// <param name="value">
        /// A <see cref="System.String"/> value to check.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsNotNullOrEmpty([AssertionCondition(AssertionConditionType.IS_NOT_NULL)] string value)
        {
            Debug.Assert(!string.IsNullOrEmpty(value), _stringIsNullOrEmptyMessage);
        }


        /// <summary>
        /// Asserts that the specified string is not <c>null</c> or empty.
        /// </summary>
        /// <param name="value">
        /// A <see cref="System.String"/> value to check.
        /// </param>
        /// <param name="message">
        /// A message to display.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsNotNullOrEmpty(
            [AssertionCondition(AssertionConditionType.IS_NOT_NULL)] string value, string message)
        {
            Debug.Assert(!string.IsNullOrEmpty(value), _stringIsNullOrEmptyMessage, message);
        }


        /// <summary>
        /// Asserts whether specified object is <c>null</c>.
        /// </summary>
        /// <param name="expected">
        /// An <see cref="System.Object"/> to check.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsNull([AssertionCondition(AssertionConditionType.IS_NULL)] object expected)
        {
            Debug.Assert(expected == null, _unexpectedNonNullValueMessage);
        }


        /// <summary>
        /// Asserts whether specified object is <c>null</c>.
        /// </summary>
        /// <param name="expected">
        /// An <see cref="System.Object"/> to check.
        /// </param>
        /// <param name="message">
        /// A message to display.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsNull([AssertionCondition(AssertionConditionType.IS_NULL)] object expected, string message)
        {
            Debug.Assert(expected == null, _unexpectedNonNullValueMessage, message);
        }


        /// <summary>
        /// Asserts whether specified object is <c>null</c>.
        /// </summary>
        /// <param name="expected">
        /// An <see cref="System.Object"/> to check.
        /// </param>
        /// <param name="messageFormat">
        /// A composite format <see cref="string"/>.
        /// </param>
        /// <param name="arguments">
        /// An array of objects to format.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsNull(
            [AssertionCondition(AssertionConditionType.IS_NULL)] object expected, 
            string messageFormat, 
            params object[] arguments)
        {
            Debug.Assert(
                expected == null, 
                _unexpectedNonNullValueMessage, 
                string.Format(CultureInfo.CurrentCulture, messageFormat, arguments));
        }


        /// <summary>
        /// Asserts that the specified string is <c>null</c> or empty.
        /// </summary>
        /// <param name="value">
        /// A <see cref="System.String"/> value to check.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsNullOrEmpty(string value)
        {
            Debug.Assert(string.IsNullOrEmpty(value), _stringIsNullOrEmptyMessage);
        }


        /// <summary>
        /// Asserts that the specified string is <c>null</c> or empty.
        /// </summary>
        /// <param name="value">
        /// A <see cref="System.String"/> value to check.
        /// </param>
        /// <param name="message">
        /// A message to display.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsNullOrEmpty(string value, string message)
        {
            Debug.Assert(string.IsNullOrEmpty(value), _stringIsNullOrEmptyMessage, message);
        }


        /// <summary>
        /// Asserts that the specified object is of specified type.
        /// </summary>
        /// <param name="instance">
        /// An instance of a <see cref="System.Object"/>.
        /// </param>
        /// <param name="type">
        /// An instance of a <see cref="System.Type"/>.
        /// </param>
        [Conditional("DEBUG")]
        public static void IsOfType(object instance, Type type)
        {
            Debug.Assert(instance.GetType() == type, _unexpectedTypeMessage);
        }


        /// <summary>
        /// Asserts that the specified object is of specified type.
        /// </summary>
        /// <param name="instance">
        /// An instance of a <see cref="System.Object"/>.
        /// </param>
        /// <param name="type">
        /// An instance of a <see cref="System.Type"/>.
        /// </param>
        /// <param name="message">
        /// A message to display.
        /// </param>
        [Conditional("DEBUG")]
        public static void IsOfType(object instance, Type type, string message)
        {
            Debug.Assert(instance.GetType() == type, _unexpectedTypeMessage, message);
        }


        /// <summary>
        /// Asserts that the specified object is of specified type.
        /// </summary>
        /// <param name="instance">
        /// An instance of a <see cref="System.Object"/>.
        /// </param>
        /// <param name="type">
        /// An instance of a <see cref="System.Type"/>.
        /// </param>
        /// <param name="detailMessageFormat">
        /// A <see cref="System.String"/> containing composite detail message format.
        /// </param>
        /// <param name="arguments">
        /// An array of objects to format.
        /// </param>
        [Conditional("DEBUG")]
        public static void IsOfType(object instance, Type type, string detailMessageFormat, params object[] arguments)
        {
            Debug.Assert(
                instance.GetType() == type, 
                _unexpectedTypeMessage, 
                string.Format(CultureInfo.CurrentCulture, detailMessageFormat, arguments));
        }


        /// <summary>
        /// Asserts whether the specified condition is <c>true</c>.
        /// </summary>
        /// <param name="condition">
        /// The evaluation condition.
        /// </param>
        /// <param name="message">
        /// A <see cref="System.String"/> containing a message.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsTrue([AssertionCondition(AssertionConditionType.IS_TRUE)] bool condition, string message)
        {
            Debug.Assert(condition, message);
        }


        /// <summary>
        /// Asserts whether the specified condition is <c>true</c>.
        /// </summary>
        /// <param name="condition">
        /// The evaluation condition.
        /// </param>
        /// <param name="messageFormat">
        /// A <see cref="System.String"/> containing a message format.
        /// </param>
        /// <param name="arguments">
        /// An array of message arguments to format.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsTrue(
            [AssertionCondition(AssertionConditionType.IS_TRUE)] bool condition, 
            string messageFormat, 
            params object[] arguments)
        {
            Debug.Assert(condition, string.Format(CultureInfo.CurrentCulture, messageFormat, arguments));
        }


        /// <summary>
        /// Asserts whether the specified condition is <c>true</c>.
        /// </summary>
        /// <param name="condition">
        /// The evaluation condition.
        /// </param>
        [Conditional("DEBUG")]
        [AssertionMethod]
        public static void IsTrue([AssertionCondition(AssertionConditionType.IS_TRUE)] bool condition)
        {
            Debug.Assert(condition, _unexpectedFalseCondition);
        }


        /// <summary>
        /// Asserts the identifier validity.
        /// </summary>
        /// <param name="identifier">
        /// An identifier to check.
        /// </param>
        [Conditional("DEBUG")]
        public static void ValidIdentifier(string identifier)
        {
            // TODO <RNovitsky, 11.02.2009>: use regexp :)
            Debug.Assert(!identifier.Contains(@" "), _invalidIdentifierMessage);
            Debug.Assert(!identifier.Contains(@"."), _invalidIdentifierMessage);
            Debug.Assert(!identifier.Contains(@"\"), _invalidIdentifierMessage);
            Debug.Assert(!identifier.Contains(@"/"), _invalidIdentifierMessage);
        }


        /// <summary>
        /// Asserts the identifier validity.
        /// </summary>
        /// <param name="identifier">
        /// An identifier to check.
        /// </param>
        /// <param name="message">
        /// A message to display.
        /// </param>
        [Conditional("DEBUG")]
        public static void ValidIdentifier(string identifier, string message)
        {
            // TODO <RNovitsky, 11.02.2009>: use regexp :)
            Debug.Assert(!identifier.Contains(@" "), _invalidIdentifierMessage, message);
            Debug.Assert(!identifier.Contains(@"."), _invalidIdentifierMessage, message);
            Debug.Assert(!identifier.Contains(@"\"), _invalidIdentifierMessage, message);
            Debug.Assert(!identifier.Contains(@"/"), _invalidIdentifierMessage, message);
        }


        /// <summary>
        /// Asserts the identifier validity.
        /// </summary>
        /// <param name="identifier">
        /// An identifier to check.
        /// </param>
        /// <param name="detailMessageFormat">
        /// A <see cref="System.String"/> containing composite detail message format.
        /// </param>
        /// <param name="arguments">
        /// An array of objects to format.
        /// </param>
        [Conditional("DEBUG")]
        public static void ValidIdentifier(string identifier, string detailMessageFormat, params object[] arguments)
        {
            // TODO <RNovitsky, 11.02.2009>: use regexp :)
            string detailMessage = string.Format(CultureInfo.CurrentCulture, detailMessageFormat, arguments);

            Debug.Assert(!identifier.Contains(@" "), _invalidIdentifierMessage, detailMessage);
            Debug.Assert(!identifier.Contains(@"."), _invalidIdentifierMessage, detailMessage);
            Debug.Assert(!identifier.Contains(@"\"), _invalidIdentifierMessage, detailMessage);
            Debug.Assert(!identifier.Contains(@"/"), _invalidIdentifierMessage, detailMessage);
        }

        [Conditional("DEBUG")]
        public static void IsNotSame(object instance1, object instance2)
        {
            Debug.Assert(ReferenceEquals(instance1, instance2), _notSameMessage);
        }

        #endregion

    }
}